When developing software applications, developers commonly spend a significant amount of time “debugging” application code to find runtime errors (e.g., undesired behaviors and software crashes) in the code. In doing so, developers may take several approaches to reproduce and locate a source code bug, such as observing behavior of a program based on different inputs, inserting debugging code (e.g., to print variable values, to track branches of execution, etc.), temporarily removing code portions, etc. Tracking down the code that causes a given undesired behavior or software crash can occupy a significant portion of application development time.
Many types of debugging software applications (“debuggers”) have been developed in order to assist developers with the code debugging process. These tools offer developers the ability to trace, visualize, and alter the execution of computer code. For example, debuggers may visualize the execution of code instructions, may present memory and register values at various times during code execution, may enable developers to alter code execution paths, and/or may enable developers to set breakpoints that pause application execution and present program state at the time the breakpoint triggers.
An emerging form of debugging applications enable “time travel,” “reverse,” or “historic” debugging, in which execution of one or more of a program's threads are recorded/traced by tracing software and/or hardware into one or more trace files. Using some tracing techniques, these trace file(s) contain a “bit-accurate” trace of each traced thread's execution, which can be then be used to replay each traced thread's execution later for forward and backward analysis. Using bit-accurate traces, each traced thread's prior execution can be reproduced down to the granularity of its individual machine code instructions.
Some trace recording techniques record a bit-accurate trace based, in part, on recording processor data influxes (e.g., cache misses, uncached reads, etc.) during execution of each traced thread's machine code instructions by the processor. These recorded processor data influxes enable a time travel debugger to later reproduce any memory values that were read by these machine code instructions during replay of a traced thread. While bit-accurate tracing can be achieved via hardware (e.g., by modifying physical processor to assist in recording data influxes to the processor), in many situations it may be advantageous to record bit-accurate traces using binary emulation, which emulates execution of subject code at a software emulator. However, binary emulation adds to the overheads of bit-accurate tracing, which can limit the situations in which bit-accurate traces can realistically be recorded in production environments.